/**
 * @Title:   [DruidConfig.java]
 * @Package: [com.yixun.qfbao.config]
 * @author:  [shaoping.jiao] 
 * @CreateDate: [2017年11月22日 下午2:25:01]   
 * @UpdateUser: [shaoping.jiao]   
 * @UpdateDate: [2017年11月22日 下午2:25:01]   
 * @Description:  [druid数据源配置]
 * @version: [V1.0]
 */
package com.yixun.qfbao.plugins.druid;

import java.sql.SQLException;

import javax.sql.DataSource;

import com.yixun.qfbao.druid.filter.config.SecurityDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName: DruidConfig
 * @author: [shaoping.jiao]
 * @CreateDate: [2017年11月22日 下午2:25:01]
 * @UpdateUser: [shaoping.jiao]
 * @UpdateDate: [2017年11月22日 下午2:25:01]
 * @Description: [druid数据源配置]
 * @version: [V1.0]
 */
@Configuration
@ConfigurationProperties(prefix = "spring.datasource")
public class DruidConfig {
	private Logger logger = LoggerFactory.getLogger(DruidConfig.class);
	
	/**
	 * 数据库链接
	 */
	private String url;
	
	/**
	 * 数据库用户名
	 */
	private String username;
	
	/**
	 * 数据库密码
	 */
	private String password;
	
	/**
	 * 数据库驱动
	 */
	private String driverClassName;
	
	/**
	 * 初始化连接数
	 */
	private int initialSize;
	
	/**
	 * 最小连接池数量
	 */
	private int minIdle;
	
	/**
	 * 最大连接池数量
	 */
	private int maxActive;
	
	/**
	 * 获取连接时最大等待时间，默认使用公平锁，可以配置useUnfairLock属性使用非公平锁
	 */
	private int maxWait;
	
	/**
	 * 有两个含义： 1. Destroy线程会检测连接的间隔时间，如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接 2.
	 * testWhileIdle的判断依据，详细看testWhileIdle属性的说明
	 */
	private int timeBetweenEvictionRunsMillis;
	
	/**
	 * 连接保持空闲而不被驱逐的最长时间
	 * 
	 */
	private int minEvictableIdleTimeMillis;
	
	/**
	 * 用来检测连接是否有效的sql，要求是一个查询语句。如果validationQuery为null，testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
	 */
	private String validationQuery;

	/**
	 * 超过时间限制是否回收
	 */
	private boolean removeAbandoned;
	/**
	 * 超时时间；单位为秒。180秒=3分钟
	 */
	private int removeAbandonedTimeout;
	/**
	 * 关闭abanded连接时输出错误日志
	 */
	private boolean logAbandoned;

	/**
	 * 建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。默认false
	 */
	private boolean testWhileIdle;
	
	/**
	 * 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。默认为true
	 */
	private boolean testOnBorrow;
	
	/**
	 * 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能 。默认为false
	 */
	private boolean testOnReturn;
	
	/**
	 * 是否缓存preparedStatement，也就是PSCache。 PSCache对支持游标的数据库性能提升巨大，比如说oracle。 在mysql下建议关闭。 默认关闭
	 */
	private boolean poolPreparedStatements;
	
	/**
	 * 要启用PSCache，必须配置大于0，当大于0时，poolPreparedStatements自动触发修改为true。在Druid中，不会存在Oracle下PSCache占用内存过多的问题，可以把这个数值配置大一些，
	 * 比如说100
	 */
	private int maxPoolPreparedStatementPerConnectionSize;
	
	/**
	 * 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有： 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
	 */
	private String filters;
	
	/**
	 * 通过connectProperties属性来打开mergeSql功能；慢SQL记录
	 */
	private String connectionProperties;
	
	@Bean(destroyMethod = "close", initMethod = "init")
	public DataSource dataSource() {
		SecurityDataSource datasource = new SecurityDataSource();
		datasource.setUrl(url);
		datasource.setUsername(username);
		datasource.setPassword(password);
		datasource.setDriverClassName(driverClassName);
		datasource.setInitialSize(initialSize);
		datasource.setMinIdle(minIdle);
		datasource.setMaxActive(maxActive);
		datasource.setMaxWait(maxWait);
		datasource.setRemoveAbandoned(removeAbandoned);
		datasource.setRemoveAbandonedTimeout(removeAbandonedTimeout);
		datasource.setLogAbandoned(logAbandoned);
		datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
		datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
		datasource.setValidationQuery(validationQuery);
		datasource.setTestWhileIdle(testWhileIdle);
		datasource.setTestOnBorrow(testOnBorrow);
		datasource.setTestOnReturn(testOnReturn);
		datasource.setPoolPreparedStatements(poolPreparedStatements);
		datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
		try {
			datasource.setFilters(filters);
		} catch (SQLException e) {
			logger.error("druid configuration initialization filter: {}", e);
		}
		datasource.setConnectionProperties(connectionProperties);
		return datasource;
	}
	
	/**
	 * @param logger the logger to set
	 */
	public void setLogger(Logger logger) {
		this.logger = logger;
	}
	
	/**
	 * @param url the url to set
	 */
	public void setUrl(String url) {
		this.url = url;
	}
	
	/**
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}
	
	/**
	 * @param password the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}
	
	/**
	 * @param driverClassName the driverClassName to set
	 */
	public void setDriverClassName(String driverClassName) {
		this.driverClassName = driverClassName;
	}
	
	/**
	 * @param initialSize the initialSize to set
	 */
	public void setInitialSize(int initialSize) {
		this.initialSize = initialSize;
	}
	
	/**
	 * @param minIdle the minIdle to set
	 */
	public void setMinIdle(int minIdle) {
		this.minIdle = minIdle;
	}
	
	/**
	 * @param maxActive the maxActive to set
	 */
	public void setMaxActive(int maxActive) {
		this.maxActive = maxActive;
	}
	
	/**
	 * @param maxWait the maxWait to set
	 */
	public void setMaxWait(int maxWait) {
		this.maxWait = maxWait;
	}
	
	/**
	 * @param timeBetweenEvictionRunsMillis the timeBetweenEvictionRunsMillis to set
	 */
	public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
		this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
	}
	
	/**
	 * @param minEvictableIdleTimeMillis the minEvictableIdleTimeMillis to set
	 */
	public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
		this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
	}
	
	/**
	 * @param validationQuery the validationQuery to set
	 */
	public void setValidationQuery(String validationQuery) {
		this.validationQuery = validationQuery;
	}

	public boolean isRemoveAbandoned() {
		return removeAbandoned;
	}

	public void setRemoveAbandoned(boolean removeAbandoned) {
		this.removeAbandoned = removeAbandoned;
	}

	public int getRemoveAbandonedTimeout() {
		return removeAbandonedTimeout;
	}

	public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
		this.removeAbandonedTimeout = removeAbandonedTimeout;
	}

	public boolean isLogAbandoned() {
		return logAbandoned;
	}

	public void setLogAbandoned(boolean logAbandoned) {
		this.logAbandoned = logAbandoned;
	}

	/**
	 * @param testWhileIdle the testWhileIdle to set
	 */
	public void setTestWhileIdle(boolean testWhileIdle) {
		this.testWhileIdle = testWhileIdle;
	}
	
	/**
	 * @param testOnBorrow the testOnBorrow to set
	 */
	public void setTestOnBorrow(boolean testOnBorrow) {
		this.testOnBorrow = testOnBorrow;
	}
	
	/**
	 * @param testOnReturn the testOnReturn to set
	 */
	public void setTestOnReturn(boolean testOnReturn) {
		this.testOnReturn = testOnReturn;
	}
	
	/**
	 * @param poolPreparedStatements the poolPreparedStatements to set
	 */
	public void setPoolPreparedStatements(boolean poolPreparedStatements) {
		this.poolPreparedStatements = poolPreparedStatements;
	}
	
	/**
	 * @param maxPoolPreparedStatementPerConnectionSize the maxPoolPreparedStatementPerConnectionSize to set
	 */
	public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
		this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
	}
	
	/**
	 * @param filters the filters to set
	 */
	public void setFilters(String filters) {
		this.filters = filters;
	}
	
	/**
	 * @param connectionProperties the connectionProperties to set
	 */
	public void setConnectionProperties(String connectionProperties) {
		this.connectionProperties = connectionProperties;
	}
}
